﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using MetadataDocumentationGenerator.DelegatesHelpers;
using MetadataDocumentationGenerator.Generator;
using MetadataDocumentationGenerator.Properties;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;

namespace MetadataDocumentationGenerator.Controls
{
    /// <summary>
    /// User control for generation progress
    /// </summary>
    public partial class Step5 : UserControl
    {
        #region Variables

        public delegate void GenerationFinishedHandler(object sender, GenerationFinishedEventArgs e);
        public event GenerationFinishedHandler GenerationFinished;

        private const string NumberOfEntitiesMask = "Entities generated : {0}/{1}";
        private const string EntityCurrentlyGeneratedMask = "Entity metadata documentation currently generated : {0}";
        

        /// <summary>
        /// Generation settings
        /// </summary>
        private readonly GenerationSettings _settings;

        private readonly List<EntityMetadata> _entityList;

        /// <summary>
        /// IOrganization service
        /// </summary>
        private readonly IOrganizationService _service;

        /// <summary>
        /// Background worker for document generation
        /// </summary>
        private BackgroundWorker _bwGenerationWorker;

        /// <summary>
        /// Generator used by the selected document type
        /// </summary>
        private IDocument2 _documentGenerator;

        #endregion Variables

        #region Constructor

        /// <summary>
        /// Initializes a new instance of class Step5
        /// </summary>
        /// <param name="settings">Generation settings</param>
        /// <param name="service">IOrganization service</param>
        /// <param name="entityList">List of entities cached for the session</param>
        public Step5(GenerationSettings settings, IOrganizationService service, List<EntityMetadata> entityList)
        {
            InitializeComponent();

            _entityList = entityList;
            _settings = settings;
            _service = service;

            lblEntitiesGenerated.Text = string.Format(NumberOfEntitiesMask, 0, _settings.EntitiesToProceed.Count);
            lblCurrentEntity.Text = string.Format(EntityCurrentlyGeneratedMask, _settings.EntitiesToProceed[0]);
        }

        #endregion Constructor

        #region User control handlers

        private void Step5Load(object sender, EventArgs e)
        {
            if (_settings.OutputDocumentType == Output.Excel)
                _documentGenerator = new ExcelDocument2(_settings);
            if (_settings.OutputDocumentType == Output.Word)
                _documentGenerator = new WordDocument2(_settings);
            //if (_settings.OutputDocumentType == Output.Csv)
            //    _documentGenerator = new CsvGenerator(_settings);

            _bwGenerationWorker = new BackgroundWorker();
            _bwGenerationWorker.RunWorkerCompleted += BwGenerateRunWorkerCompleted;
            _bwGenerationWorker.ProgressChanged += BwGenerateProgressChanged;
            _bwGenerationWorker.DoWork += BwGenerateDoWork;
            _bwGenerationWorker.WorkerReportsProgress = true;
            _bwGenerationWorker.WorkerSupportsCancellation = true;
            _bwGenerationWorker.RunWorkerAsync();
        }

        #endregion User control handlers

        #region Methods

        private void BwGenerateDoWork(object sender, DoWorkEventArgs e)
        {
            _documentGenerator.Generate(TriggerProgressChanged, _service, _entityList);
            e.Result = _documentGenerator;
            LabelDelegates.SetText(lblCurrentEntity, string.Empty);
        }

        private void TriggerProgressChanged(GenerationProgress gp)
        {
            _bwGenerationWorker.ReportProgress(gp.CurrentStep/gp.TotalSteps*100, gp);
        }
        
        private void BwGenerateProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var gp = (GenerationProgress)e.UserState;
            LabelDelegates.SetText(lblEntitiesGenerated, 
                string.Format(NumberOfEntitiesMask, gp.CurrentStep, _settings.EntitiesToProceed.Count));

            LabelDelegates.SetText(lblCurrentEntity, string.Format(EntityCurrentlyGeneratedMask, gp.CurrentEntity));
        }

        private void BwGenerateRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            string filePath = null;

            if (e.Error == null)
            {
                var document = e.Result as IDocument2;
                if (document != null)
                {
                    if (document.IsMultipleOutput)
                    {
                        var fbd = new FolderBrowserDialog();

                        if (fbd.ShowDialog() == DialogResult.OK)
                        {
                            document.SaveDocument(fbd.SelectedPath);
                            filePath = fbd.SelectedPath;
                        }
                    }
                    else
                    {
                        var sfd = new SaveFileDialog
                        {
                            Title = Resources.ExcelSaveDialogTitle,
                            Filter = document.Filter
                        };

                        if (sfd.ShowDialog() == DialogResult.OK)
                        {
                            document.SaveDocument(sfd.FileName);
                            filePath = sfd.FileName;
                        }
                    }
                    
                }
            }
            else
            {
                MessageBox.Show(Resources.GeneratingDocumentErrorDescription + e.Error, Resources.MessageBoxErrorHeader, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            if (GenerationFinished != null)
            {
                GenerationFinished(this, new GenerationFinishedEventArgs { FilePath = filePath });
            }
        }

        #endregion
    }

    /// <summary>
    /// Event args for generation finished
    /// </summary>
    public class GenerationFinishedEventArgs : EventArgs
    {
        public string FilePath { get; set; }
    }
}
